package com.zyx.concurrentdemo.mytest.c08;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * @author Yaxi.Zhang
 * @since 2021/10/20 09:41
 */
@Slf4j(topic = "c.ForkJoinDemo")
public class ForkJoinDemo {

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool(4);
        //log.debug("finally result =====>>>>> {}", pool.invoke(new ForkJoinTask1(5)));
        log.debug("finally result =====>>>>> {}", pool.invoke(new ForkJoinTask2(1, 5)));
    }

}

@Slf4j(topic = "c.ForkJoinTask1")
class ForkJoinTask1 extends RecursiveTask<Integer> {

    int n;

    public ForkJoinTask1(int n) {
        this.n = n;
    }

    @Override
    public String toString() {
        return "ForkJoinTask1{" +
                "n=" + n +
                '}';
    }

    @Override
    protected Integer compute() {

        if (n == 1) {
            log.debug("join() {}", n);
            return 1;
        }

        ForkJoinTask1 task = new ForkJoinTask1(n - 1);
        task.fork();

        log.debug("fork() {} + {}", n, task);
        int result = n + task.join();
        log.debug("join() {} + {} = {}", n, task, result);

        return result;
    }
}

@Slf4j(topic = "c.ForkJoinTask2")
class ForkJoinTask2 extends RecursiveTask<Integer> {

    int begin;
    int end;

    public ForkJoinTask2(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if (begin == end) {
            log.debug("join() {}", begin);
            return begin;
        }
        if (end - begin == 1) {
            log.debug("join() {} + {} = {}", begin, end, end + begin);
            return begin + end;
        }

        int mid = (begin + end) >> 1;

        ForkJoinTask2 left = new ForkJoinTask2(begin, mid);
        ForkJoinTask2 right = new ForkJoinTask2(mid + 1, end);

        left.fork();
        right.fork();

        log.debug("fork() {} + {} + {} = ?", mid, left, right);

        int result = left.join() + right.join();

        log.debug("join() {} + {} + {} = {}", mid, left, right, result);

        return result;
    }
}
